package baidu_uid

import "errors"

type BitsAllocator struct {
	/**
	Bits for [sign-> second-> workId-> sequence]
	*/
	//signBits      int64
	timestampBits int64
	workerIdBits  int64
	sequenceBits  int64

	/**
	Max value for workId & sequence
	*/
	maxDeltaSeconds int64
	maxWorkerId     int64
	maxSequence     int64

	/**
	Shift for timestamp & workerId
	*/

	timestampShift int64
	workerIdShift  int64
}

func NewBitsAllocatorDefault() *BitsAllocator {
	b, _ := NewBitsAllocator(DELTA_LEN, WORK_NODE_LEN, SEQUENCE_LEN)
	return b
}

func NewBitsAllocator(timestampBits int64, workerIdBits int64, sequenceBits int64) (*BitsAllocator, error) {
	// make sure allocated 64 bits
	allocateTotalBits := SIGN_BITS + timestampBits + workerIdBits + sequenceBits
	if allocateTotalBits != TOTAL_BITS {
		return nil, errors.New("allocate not enough 64 bits")
	}

	return &BitsAllocator{
		// initialize bits
		timestampBits: timestampBits,
		workerIdBits:  workerIdBits,
		sequenceBits:  sequenceBits,

		// initialize max value
		maxDeltaSeconds: ^(-1 << timestampBits),
		maxWorkerId:     ^(-1 << workerIdBits),
		maxSequence:     ^(-1 << sequenceBits),

		// initialize shift
		timestampShift: workerIdBits + sequenceBits,
		workerIdShift:  sequenceBits,
	}, nil

}

func (ba *BitsAllocator) allocate(deltaSeconds int64, workerId int64, sequence int64) int64 {
	return (deltaSeconds << ba.timestampShift) | (workerId << ba.workerIdShift) | sequence
}

func (ba *BitsAllocator) getSignBits() int64 {
	return SIGN_BITS
}

func (ba *BitsAllocator) getTimestampBits() int64 {
	return ba.timestampBits
}

func (ba *BitsAllocator) getWorkerIdBits() int64 {
	return ba.workerIdBits
}

func (ba *BitsAllocator) getSequenceBits() int64 {
	return ba.sequenceBits
}

func (ba *BitsAllocator) getMaxDeltaSeconds() int64 {
	return ba.maxDeltaSeconds
}

func (ba *BitsAllocator) getMaxWorkerId() int64 {
	return ba.maxWorkerId
}

func (ba *BitsAllocator) getMaxSequence() int64 {
	return ba.maxSequence
}

func (ba *BitsAllocator) getTimestampShift() int64 {
	return ba.timestampShift
}

func (ba *BitsAllocator) getWorkerIdShift() int64 {
	return ba.workerIdShift
}
